// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	2/16/2015 8:05:31 PM				
// -----------------------------

#include "CGraphicsDevice.h"

#include "IWindow.h"
#include "WindowEventHandler.h"

namespace Flow
{

	CGraphicsDevice::CGraphicsDevice()
	{
	}

	CGraphicsDevice::~CGraphicsDevice()
	{
	}

	void CGraphicsDevice::Release()
	{
		delete this;
	}

	Bool CGraphicsDevice::Initialize(IWindow* lpWindow)
	{
		// Create the Create Device Flags
		UInt32 createDeviceFlags = 0;
		#ifdef _DEBUG
		createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
		#endif

		// Setup the Feature Levels
		D3D_FEATURE_LEVEL featureLevels[] =
		{
			D3D_FEATURE_LEVEL_9_3,
		};
		UInt32 featureLevelCount = ARRAYSIZE(featureLevels);

		// Create the Device & Device Context
		ComPtr<ID3D11Device> dxDevice;
		ComPtr<ID3D11DeviceContext> dxDeviceContext;
		HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevels, featureLevelCount, D3D11_SDK_VERSION, &dxDevice, NULL, &dxDeviceContext);
		if (FAILED(hr))
			return false;

		// Interpret the Device & Device Context
		hr = dxDevice.As(&m_Device);
		if (FAILED(hr))
			return false;
		hr = dxDeviceContext.As(&m_DeviceContext);
		if (FAILED(hr))
			return false;

		return InitializeView(lpWindow);
	}
	Bool CGraphicsDevice::InitializeView(IWindow* lpWindow)
	{
		// Setup the Swapchain Descriptor
		DXGI_SWAP_CHAIN_DESC1 swapDesc = {};
		swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
		swapDesc.Stereo = false;
		swapDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
		swapDesc.SampleDesc.Quality = 0;
		swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapDesc.BufferCount = 1; // On phone, only single buffering is supported.
		swapDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
		swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
		swapDesc.Flags = 0;

		// Get the DXGIGraphicsDevice1
		ComPtr<IDXGIDevice1> dxgiDevice;
		HRESULT hr = m_Device.As(&dxgiDevice);
		if (FAILED(hr))
			return false;

		// Get the DXGIAdapter
		ComPtr<IDXGIAdapter> dxgiAdapter;
		hr = dxgiDevice->GetAdapter(&dxgiAdapter);
		if (FAILED(hr))
			return false;

		// Get the DXGIFactory2
		ComPtr<IDXGIFactory2> dxgiFactory;
		hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), &dxgiFactory);
		if (FAILED(hr))
			return false;

		// Create the Swapchain
		hr = dxgiFactory->CreateSwapChainForCoreWindow(m_Device.Get(), reinterpret_cast<IUnknown*>(WindowEventHandler::Window), &swapDesc, NULL, &m_SwapChain);
		if (FAILED(hr))
			return false;

		// Get the Backbuffer Texture
		ComPtr<ID3D11Texture2D> backBuffer;
		hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer);
		if (FAILED(hr))
			return false;

		// Create the Backbuffer View
		hr = m_Device->CreateRenderTargetView(backBuffer.Get(), NULL, &m_BackBufferView);
		if (FAILED(hr))
			return false;

		// Query the Backbuffer Dimensions
		D3D11_TEXTURE2D_DESC backBufferDesc = {};
		backBuffer->GetDesc(&backBufferDesc);

		// Create the Depth Stencil Texture
		D3D11_TEXTURE2D_DESC depthDesc = {};
		depthDesc.ArraySize = 1;
		depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
		depthDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
		depthDesc.MipLevels = 1;
		depthDesc.SampleDesc.Count = 1;
		depthDesc.SampleDesc.Quality;
		depthDesc.Usage = D3D11_USAGE_DEFAULT;
		depthDesc.Width = backBufferDesc.Width;
		depthDesc.Height = backBufferDesc.Height;

		hr = m_Device->CreateTexture2D(&depthDesc, NULL, &m_DepthStencil);
		if (FAILED(hr))
			return false;

		// Create the Depth Stencil View
		D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc = {};
		depthViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;

		hr = m_Device->CreateDepthStencilView(m_DepthStencil.Get(), &depthViewDesc, &m_DepthStencilView);
		if (FAILED(hr))
			return false;

		return true;
	}

	void CGraphicsDevice::Begin(Float r, Float g, Float b) const
	{
		Float rgba[] = { r, g, b, 1.0f };
		m_DeviceContext->ClearDepthStencilView(m_DepthStencilView.Get(), 0, 1.0f, 0x00);
		m_DeviceContext->ClearRenderTargetView(m_BackBufferView.Get(), rgba);

		ID3D11RenderTargetView* renderTargets[] = { m_BackBufferView.Get() };
		m_DeviceContext->OMSetRenderTargets(1, renderTargets, m_DepthStencilView.Get());
	}
	void CGraphicsDevice::End() const
	{
		m_SwapChain->Present(1, 0);

		m_DeviceContext->DiscardView(m_BackBufferView.Get());
		m_DeviceContext->DiscardView(m_DepthStencilView.Get());
	}

}